package com.apexedu.portal.util;

import com.apexedu.framework.util.SysPropertiesUtil;
import com.apexedu.identity.entity.TSysDepart;
import com.apexedu.identity.entity.TSysUser;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

/**
 * Created by ly on 2014/9/10.
 */
public class LdapUtil {
    protected Log log = LogFactory.getLog(this.getClass());//日志记录

    private static DirContext ctx;
    static final String ldapHost = SysPropertiesUtil.get("ldapHost");
    static final String ldapPort = SysPropertiesUtil.get("ldapPort");
    static final String ldapBindDN = SysPropertiesUtil.get("ldapBindDN");
    static final String ldapPassword = SysPropertiesUtil.get("ldapPassword");
    static final String organizationName = SysPropertiesUtil.get("organizationName");

    /**
     * 获取连接
     *
     * @return
     */
    public static DirContext getCtx() {
        ClassLoader cl = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                return super.loadClass(name);
            }
        };
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, "ldap://" + ldapHost + ":" + ldapPort
                + "");
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        //ldapBindDN 需要傳參數
        env.put(Context.SECURITY_PRINCIPAL, ldapBindDN);
        env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
        try {
            // 链接ldap
            ctx = new InitialDirContext(env);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ctx;
    }

    /**
     * 字符串转码
     *
     * @param msg
     * @return
     */
    private static String convertUTF8(String msg) {
//        try {
//            return new String(msg.getBytes("ISO-8859-1"), "UTF-8");
//        } catch (UnsupportedEncodingException e) {
//            e.printStackTrace();
//        }
        return msg;
    }

    public static boolean verifySHA(String ldappw, String inputpw)
            throws NoSuchAlgorithmException {
        // MessageDigest 提供了消息摘要算法，如 MD5 或 SHA，的功能，这里LDAP使用的是SHA-1
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        // 取出加密字符
        if (ldappw.startsWith("{SSHA}")) {
            ldappw = ldappw.substring(6);
        } else if (ldappw.startsWith("{SHA}")) {
            ldappw = ldappw.substring(5);
        }
        // 解码BASE64
        byte[] ldappwbyte = Base64.decode(ldappw);
        byte[] shacode;
        byte[] salt;
        // 前20位是SHA-1加密段，20位后是最初加密时的随机明文
        if (ldappwbyte.length <= 20) {
            shacode = ldappwbyte;
            salt = new byte[0];
        } else {
            shacode = new byte[20];
            salt = new byte[ldappwbyte.length - 20];
            System.arraycopy(ldappwbyte, 0, shacode, 0, 20);
            System.arraycopy(ldappwbyte, 20, salt, 0, salt.length);
        }
        // 把用户输入的密码添加到摘要计算信息
        md.update(inputpw.getBytes());
        // 把随机明文添加到摘要计算信息
        md.update(salt);
        // 按SSHA把当前用户密码进行计算
        byte[] inputpwbyte = md.digest();
        // 返回校验结果
        return MessageDigest.isEqual(shacode, inputpwbyte);
    }

    /**
     * 验证
     *
     * @return
     */
    public static boolean authenticate(String usr, String pwd) {
        boolean success = false;
        DirContext ctx = null;
        try {
            ctx = getCtx();
            SearchControls constraints = new SearchControls();
            constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
            // constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
            NamingEnumeration en = ctx.search("", "cn=" + usr, constraints); // 查询所有用户
            while (en != null && en.hasMoreElements()) {
                Object obj = en.nextElement();
                if (obj instanceof SearchResult) {
                    SearchResult si = (SearchResult) obj;
                    Attributes attrs = si.getAttributes();
                    if (attrs == null) {
                        System.out.println("No   attributes");
                    } else {
                        Attribute attr = attrs.get("userPassword");
                        Object o = attr.get();
                        byte[] s = (byte[]) o;
                        String pwd2 = new String(s);
                        success = verifySHA(pwd2, pwd);
                        return success;
                    }
                } else {
                    System.out.println(obj);
                }
                success = true;
            }
            ctx.close();
        } catch (NoSuchAlgorithmException ex) {
            try {
                if (ctx != null) {
                    ctx.close();
                }
            } catch (NamingException namingException) {
                namingException.printStackTrace();
            }
        } catch (NamingException ex) {
            try {
                if (ctx != null) {
                    ctx.close();
                }
            } catch (NamingException namingException) {
                namingException.printStackTrace();
            }
        }
        return success;
    }

    /**
     * 创建组织
     *
     * @return
     */
    public static boolean createO() {
        boolean success = false;
        DirContext ctx = null;
        try {
            ctx = getCtx();
            BasicAttributes attrsbu = new BasicAttributes();
            BasicAttribute objclassSet = new BasicAttribute("objectclass");
            objclassSet.add("top");
            objclassSet.add("organization");
            attrsbu.put(objclassSet);
            attrsbu.put("o", convertUTF8(organizationName));
            ctx.createSubcontext("o=" + convertUTF8(organizationName) + ",dc=shgyjs,dc=com", attrsbu);
            ctx.close();
            success = true;
        } catch (Exception ex) {
            try {
                if (ctx != null) {
                    ctx.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return success;
    }

    public static boolean removeO() {
        boolean success = false;
        DirContext ctx = null;
        try {
            ctx = getCtx();
            SearchControls constraints = new SearchControls();
            constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
            // constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
            NamingEnumeration en = ctx.search("", "objectclass=organizationalPerson", constraints); // 查询所有用户
            List<String> list = new ArrayList<String>();
            while (en != null && en.hasMoreElements()) {
                Object obj = en.nextElement();
                if (obj instanceof SearchResult) {
                    SearchResult si = (SearchResult) obj;
                    if (si.getName().indexOf("o=上海市工业技术学校,dc=shgyjs,dc=com") > 0 && si.getName().indexOf("uid") == 0 && si.getName().indexOf("ou=学生") == -1)
                        list.add(si.getName());
                }
            }
//            ctx.destroySubcontext("o=南京顶点大学,dc=shgyjs,dc=com");
            for (String str : list) {
                ctx.destroySubcontext(str);
            }
            ctx.close();
            success = true;
        } catch (Exception ex) {
            try {
                if (ctx != null) {
                    ctx.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return success;
    }

    /**
     * 创建组织单元
     *
     * @param ou
     * @return
     */
    public static boolean createOU(String ou) {
        boolean success = false;
        DirContext ctx = null;
        try {
            ctx = getCtx();
            BasicAttributes attrsbu = new BasicAttributes();
            BasicAttribute objclassSet = new BasicAttribute("objectclass");
            objclassSet.add("top");
            objclassSet.add("organizationalUnit");
            attrsbu.put(objclassSet);
            attrsbu.put("ou", ou);
            ctx.createSubcontext("ou=" + ou + ",o = " + convertUTF8(organizationName) + ",dc=shgyjs,dc=com", attrsbu);
            ctx.close();
            success = true;
        } catch (NamingException ex) {
            try {
                if (ctx != null) {
                    ctx.close();
                }
            } catch (NamingException namingException) {
                namingException.printStackTrace();
            }
        }
        return success;
    }

    /**
     * 添加用户
     *
     * @param user
     * @return
     */
    public static boolean addUser(TSysUser user) {
        boolean success = false;
        DirContext ctx = null;
        try {
            ctx = getCtx();
            BasicAttributes attrsbu = new BasicAttributes();
            BasicAttribute objclassSet = new BasicAttribute("objectclass");
            objclassSet.add("person");
            objclassSet.add("top");
            objclassSet.add("organizationalPerson");
            objclassSet.add("inetOrgPerson");
            attrsbu.put(objclassSet);
            attrsbu.put("cn", user.getUsername());
            attrsbu.put("sn", user.getUsername());
//          attrsbu.put("uid", user.getUserloginid());
            attrsbu.put("userPassword", user.getUserpwd());
            ctx.createSubcontext(
                    "uid=" + user.getUserloginid() + ",ou=" + user.getOrname() + ",o="
                            + convertUTF8(organizationName)
                            + ",dc=shgyjs,dc=com", attrsbu
            );
            ctx.close();
            success = true;
        } catch (NamingException ex) {
            try {
                if (ctx != null) {
                    ctx.close();
                }
            } catch (NamingException namingException) {
                namingException.printStackTrace();
            }
        }
        return success;
    }

    /**
     * 修改密码
     *
     * @param usr
     * @param pwd
     * @return
     */
    public static boolean updatePwdLdap(String usr, String pwd) {
        boolean success = false;
        DirContext ctx = null;
        String cn = "";
        cn = queryLdap(usr);
        if ("".equals(cn)) {
            return success;
        } else {
            try {
                ctx = getCtx();
                ModificationItem[] modificationItem = new ModificationItem[1];
                modificationItem[0] = new ModificationItem(
                        DirContext.REPLACE_ATTRIBUTE, new BasicAttribute(
                        "userPassword", pwd)
                );
                ctx.modifyAttributes(cn, modificationItem);
                ctx.close();
                return true;
            } catch (NamingException ex) {
                ex.printStackTrace();
                try {
                    if (ctx != null) {
                        ctx.close();
                    }
                } catch (NamingException namingException) {
                    namingException.printStackTrace();
                }
            }
        }
        return success;
    }

    public static String queryPwd(String usr) {
        String result = "";
        DirContext ctx = null;
        try {
            ctx = getCtx();
            SearchControls constraints = new SearchControls();
            constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
            // constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
            NamingEnumeration en = ctx.search("", "(cn=" + usr + ")", constraints); // 查询所有用户
//            NamingEnumeration en = ctx.search("", "cn=" + usr, constraints); // 查询所有用户
            while (en != null && en.hasMoreElements()) {
                Object obj = en.nextElement();
                if (obj instanceof SearchResult) {
                    SearchResult si = (SearchResult) obj;
                    if (si.getAttributes().get("cn") != null && usr.equals(si.getAttributes().get("cn").get().toString())) {
                        Attribute attr = si.getAttributes().get("userPassword");
                        Object o = attr.get();
                        byte[] s = (byte[]) o;
                        result = new String(s);
                    }
                }
            }
        } catch (NamingException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (ctx != null) {
                    ctx.close();
                }
            } catch (NamingException namingException) {
                namingException.printStackTrace();
            }
        }
        return result;
    }

    public static String queryLdap(String usr) {
        String result = "";
        DirContext ctx = null;
        try {
            ctx = getCtx();
            SearchControls constraints = new SearchControls();
            constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
            // constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
            NamingEnumeration en = ctx.search("", "(uid=" + usr + ")", constraints); // 查询所有用户
            while (en != null && en.hasMoreElements()) {
                Object obj = en.nextElement();
                if (obj instanceof SearchResult) {
                    SearchResult si = (SearchResult) obj;
                    if (si.getAttributes().get("cn") != null && usr.equals(si.getAttributes().get("cn").get().toString())) {
                        result = si.getName();
                    }
                }
            }
            ctx.close();
        } catch (NamingException ex) {
            try {
                if (ctx != null) {
                    ctx.close();
                }
            } catch (NamingException namingException) {
                namingException.printStackTrace();
            }
        }
        return result;
    }

    public static boolean deleteEntry(String usr) {
        boolean success = false;
        DirContext ctx = null;
        try {
            ctx = getCtx();
            SearchControls constraints = new SearchControls();
            constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
            // constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
            NamingEnumeration en = ctx.search("", "(uid=" + usr+")", constraints); // 查询所有用户
            while (en != null && en.hasMoreElements()) {
                Object obj = en.nextElement();
                if (obj instanceof SearchResult) {
                    SearchResult si = (SearchResult) obj;
                    ctx.destroySubcontext(si.getName());
                }
                success = true;
            }
            ctx.close();
        } catch (NamingException ex) {
            try {
                if (ctx != null) {
                    ctx.close();
                }
            } catch (NamingException namingException) {
                namingException.printStackTrace();
            }
        }
        return success;
    }

    /**
     * 创建组织机构
     *
     * @param departList
     * @return
     */
    public static boolean createOuTempAll(List<TSysDepart> departList) {
        for (TSysDepart depart : departList) {
            createOU(depart.getDepartname() + "_" + depart.getDepartcode());
        }
        return true;
    }

    /**
     * 批量添加用户
     *
     * @param list
     * @return
     */
    public static boolean addUserTempAll(List<TSysUser> list) {
        for (TSysUser user : list) {
            addUser(user);
        }
        return false;
    }
}
